package com.yexiao.cofe.business.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.hash.Hash;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yexiao.cofe.business.mapper.*;
import com.yexiao.cofe.business.pojo.*;
import com.yexiao.cofe.business.service.StoreService;
import com.yexiao.cofe.common.exception.BusinessException;
import com.yexiao.cofe.constant.ProductConstant;
import com.yexiao.cofe.constant.StoreConstant;
import com.yexiao.cofe.util.SystemUtil;
import com.yexiao.core.util.IDateUtil;
import com.yexiao.core.util.JSONUtil;
import com.yexiao.core.util.StrUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class StoreServiceImpl implements StoreService {
    
    @Resource
    private StoreMapper storeMapper;
    @Resource
    private StoreProductMapper storeProductMapper;
    @Resource
    private ProductMapper productMapper;
    @Resource
    private ParamTemplateMapper templateMapper;
    @Resource
    private TemplateParamMapper templateParamMapper;
    @Resource
    private CategoryMapper categoryMapper;
    @Resource
    private ParamItemMapper paramItemMapper;
    @Resource
    private ParamValueMapper paramValueMapper;

    @Override
    public List<JSONObject> listAll(JSONObject param,  String token) {
        List<Store> stores = storeMapper.selectList(null);

        List<JSONObject> res = new ArrayList<>();
        for (Store store : stores) {
            res.add(Store.getBaseMsg(store));
        }
        
        return res;
    }

    @Override
    public void addStore(JSONObject param,  String token) {
        String storeName = JSONUtil.checkAndGetStr(param, "storeName");
        String address = JSONUtil.checkAndGetStr(param, "address");
        String phone = JSONUtil.checkAndGetStr(param, "phone");
        String openingHours = JSONUtil.checkAndGetStr(param, "openingHours");
        String coverImage = JSONUtil.checkAndGetStr(param, "coverImage");

        if("公共门店".equals(storeName)) {
            throw new BusinessException("非法店铺名");
        }


        String storeId = generateStoreId();
        while(storeMapper.selectByStoreId(storeId) != null) {
            storeId = generateStoreId();
        }

        Store store = new Store();
        store.setName(storeName)
                .setStoreId(storeId)
                .setAddress(address)
                .setPhone(phone)
                .setOpeningHours(openingHours)
                .setCoverImage(coverImage)
                .setStatus(StoreConstant.Store_Status_Stop);

        storeMapper.insert(store);
    }

    @Override
    public void modify(JSONObject param,  String token) {
        String storeId = JSONUtil.checkAndGetStr(param, "storeId");
        String name = JSONUtil.getStr(param, "name");
        String address = JSONUtil.getStr(param, "address");
        String phone = JSONUtil.getStr(param, "phone");
        String openingHours = JSONUtil.getStr(param, "openingHours");
        String coverImage = JSONUtil.getStr(param, "coverImage");
        Integer sort = JSONUtil.getInt(param, "sort");

        storeMapper.modifyStoreMsg(storeId, name, address, phone, openingHours, coverImage, sort);
    }

    @Override
    public List<JSONObject> listProduct(JSONObject param,  String token) {
        String storeId = JSONUtil.checkAndGetStr(param, "storeId");
        List<StoreProduct> storeProductList = storeProductMapper.selectByStoreId(storeId);
        List<Integer> productIdList = storeProductList.stream().map(StoreProduct::getProductId).collect(Collectors.toList());

        List<JSONObject> res = new ArrayList<>();
        List<Product> productList = listProduct(productIdList);
        List<Category> categoryList = categoryMapper.listAll();
        Map<Integer, Category> categoryMap = categoryList.stream().collect(Collectors.toMap(Category::getId, p -> p));

        // 获取模板信息
        List<Integer> templateIdList = storeProductList.stream().map(StoreProduct::getParamTemplateId).collect(Collectors.toList());
        List<ParamTemplate> templateList = listTemplate(templateIdList);
        Map<Integer, ParamTemplate> templateMap = new HashMap<>(16);
        for (StoreProduct storeProduct : storeProductList) {
            int paramTemplateId = storeProduct.getParamTemplateId();
            for (ParamTemplate template : templateList) {
                if(template.getId() == paramTemplateId) {
                    templateMap.put(storeProduct.getProductId(), template);
                }
            }
        }

        // 按分类筛选、返回商品
        Map<Integer, List<Product>> productMap = new HashMap<>();
        for (Product product : productList) {
            int categoryId = product.getCategoryId();
            List<Product> list = productMap.getOrDefault(categoryId, new ArrayList<>());
            list.add(product);
            productMap.put(categoryId, list);
        }

        for (Map.Entry<Integer, List<Product>> entry : productMap.entrySet()) {
            Integer categoryId = entry.getKey();
            List<Product> list = entry.getValue();
            Category category = categoryMap.get(categoryId);
            SystemUtil.checkErrorIfNull(category, "分类不存在");

            JSONObject node = JSONUtil.of(
                    "categoryId", category.getId(),
                    "categoryName", category.getName()
            );

            List<JSONObject> resList = new ArrayList<>();
            for (Product product : list) {
                JSONObject baseMsg = Product.getBaseMsg(product);
                ParamTemplate template = templateMap.get(product.getProductId());
                baseMsg.put("templateId", template.getId());
                baseMsg.put("templateName", template.getName());
                resList.add(baseMsg);
            }
            node.put("productList", resList);
            res.add(node);
        }

        return res;
    }

    private List<ParamTemplate> listTemplate(List<Integer> templateIdList) {
        List<ParamTemplate> res = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(templateIdList)) {
            QueryWrapper<ParamTemplate> wrapper = new QueryWrapper<>();
            wrapper.in(ParamTemplate.ID, templateIdList);
            res = templateMapper.selectList(wrapper);
        }
        return res;
    }

    @Override
    public JSONObject detail(JSONObject param,  String token) {
        String storeId = JSONUtil.checkAndGetStr(param, "storeId");
        Store store = storeMapper.selectByStoreId(storeId);

        return Store.getBaseMsg(store);
    }

    @Override
    public void modifyStatus(JSONObject param,  String token) {
        String storeId = JSONUtil.checkAndGetStr(param, "storeId");
        Integer status = JSONUtil.checkAndGetInt(param, "status");
        storeMapper.modifyStatus(storeId, status);
    }

    @Override
    public void bindProduct(JSONObject param, String token) {
        User user = SystemUtil.getUser(token);
        String storeId = JSONUtil.checkAndGetStr(param, "storeId");
        Integer productId = JSONUtil.checkAndGetInt(param, "productId");
        Integer templateId = JSONUtil.getInt(param, "templateId");
        String price = JSONUtil.checkAndGetStr(param, "price");

        Store store = storeMapper.selectByStoreId(storeId);
        SystemUtil.checkErrorIfNull(store, "门店不存在");

        Product product = productMapper.getProduct(productId);
        SystemUtil.checkErrorIfNull(product, "商品不存在");

        ParamTemplate template = null;
        if(templateId != null) {
            template = templateMapper.selectById(templateId);
            SystemUtil.checkErrorIfNull(template, "模板不存在");
        }

        StoreProduct storeProductTemp = storeProductMapper.selectByStoreIdAndProductId(storeId, productId);
        SystemUtil.checkErrorIfNotNull(storeProductTemp, "商品已绑定");


        String now = IDateUtil.now();
        StoreProduct storeProduct = new StoreProduct();
        storeProduct.setProductId(productId)
                .setStoreId(storeId)
                .setPrice(new BigDecimal(price))
                .setStatus(ProductConstant.Product_Status_Down)
                .setCreateTime(now)
                .setCreateUser(user.getUserName())
                .setUpdateTime(now)
                .setUpdateUser(user.getUserName());
        if(template != null) {
            storeProduct.setParamTemplateId(templateId);
        }

        storeProductMapper.insert(storeProduct);
    }

    @Override
    @Transactional
    public void copyProduct(JSONObject param, String token) {
        String sourceStoreId = JSONUtil.checkAndGetStr(param, "sourceStoreId");
        Integer sourceProductId = JSONUtil.checkAndGetInt(param, "sourceProductId");
        String storeId = JSONUtil.checkAndGetStr(param, "targetStoreId");

        // 合理性校验
        Store publicStore;
        List<Store> list = storeMapper.listStore("公共门店");
        if(CollectionUtil.isNotEmpty(list)) {
            publicStore = list.get(0);
        } else {
            throw new BusinessException("公共门店不存在");
        }
        if(StrUtil.notEquals(publicStore.getStoreId(), sourceStoreId)) {
            throw new BusinessException("仅能从公共门店复制商品配置");
        }
        Store store = storeMapper.selectByStoreId(storeId);
        if(store == null) {
            throw new BusinessException("目标门店不存在");
        }
        Product product = productMapper.getProduct(sourceProductId);
        if(product == null) {
            throw new BusinessException("商品不存在");
        }
        StoreProduct storeProduct1 = storeProductMapper.selectByStoreIdAndProductId(storeId, sourceProductId);
        if(storeProduct1 != null) {
            throw new BusinessException("商品已存在，如需复制商品配置，请先删除本店商品");
        }
        StoreProduct storeProduct = storeProductMapper.selectByStoreIdAndProductId(sourceStoreId, sourceProductId);
        if(storeProduct == null) {
            throw new BusinessException("公共门店未绑定商品");
        }
        ParamTemplate template = templateMapper.selectById(storeProduct.getParamTemplateId());
        if(template == null) {
            throw new BusinessException("参数模板不存在");
        }

        // 复制模板
        ParamTemplate paramTemplate = new ParamTemplate();
        BeanUtils.copyProperties(template, paramTemplate);
        paramTemplate.setId(null);
        paramTemplate.setStoreId(storeId);
        templateMapper.insert(paramTemplate);

        // 复制模板参数
        List<TemplateParam> templateParamList = templateParamMapper.selectByTemplateId(template.getId());
        List<TemplateParam> newTemplateParamList = new ArrayList<>();
        for (TemplateParam templateParam : templateParamList) {
            TemplateParam temp = new TemplateParam();
            BeanUtils.copyProperties(templateParam, temp);
            temp.setId(null);
            temp.setTemplateId(paramTemplate.getId());
            newTemplateParamList.add(temp);
        }
        templateParamMapper.insert(newTemplateParamList);

        // 复制商品
        StoreProduct newStoreProduct = new StoreProduct();
        BeanUtils.copyProperties(storeProduct, newStoreProduct);
        newStoreProduct.setStoreId(storeId)
                .setParamTemplateId(paramTemplate.getId());
        newStoreProduct.setId(null);
        storeProductMapper.insert(newStoreProduct);
    }

    @Override
    public void changeTemplate(JSONObject param, String token) {
        String storeId = JSONUtil.checkAndGetStr(param, "storeId");
        Integer productId = JSONUtil.checkAndGetInt(param, "productId");
        Integer templateId = JSONUtil.checkAndGetInt(param, "templateId");

        StoreProduct storeProduct = storeProductMapper.selectByStoreIdAndProductId(storeId, productId);
        if(storeProduct == null) {
            throw new BusinessException("操作异常");
        }
        if(storeProduct.getParamTemplateId() == templateId) {
            throw new BusinessException("无法绑定相同模板");
        }
        ParamTemplate paramTemplate = templateMapper.selectById(templateId);
        if(paramTemplate == null) {
            throw new BusinessException("模板不存在");
        }
        if(StrUtil.notEquals(paramTemplate.getStoreId(), storeId)) {
            throw new BusinessException("仅能绑定本店模板");
        }
        storeProduct.setParamTemplateId(paramTemplate.getId());
        storeProductMapper.updateById(storeProduct);
    }

    @Override
    public JSONObject storeProductDetail(JSONObject param, String token) {
        String storeId = JSONUtil.checkAndGetStr(param, "storeId");
        Integer productId = JSONUtil.checkAndGetInt(param, "productId");

        Product product = productMapper.getProduct(productId);
        SystemUtil.checkErrorIfNull(product, "商品不存在");

        // 商品参数详情
        StoreProduct storeProduct = storeProductMapper.selectByStoreIdAndProductId(storeId, productId);
        int templateId = storeProduct.getParamTemplateId();
        ParamTemplate template = templateMapper.selectById(templateId);
        List<ParamItem> paramItemList = paramItemMapper.listAll();
        List<ParamValue> paramValueList = paramValueMapper.listAll();
        List<TemplateParam> templateParamList = templateParamMapper.selectByTemplateId(templateId);
        List<JSONObject> paramList = getTemplateDetail(templateParamList, paramItemList, paramValueList);

        JSONObject res = Product.getBaseMsg(product);
        res.put("templateId", templateId);
        res.put("templateName", template.getName());
        res.put("templateDescription", template.getDescription());
        res.put("paramList", paramList);

        return res;
    }

    @Override
    @Transactional
    public void delStoreProduct(JSONObject param, String token) {
        String storeId = JSONUtil.checkAndGetStr(param, "storeId");
        Integer productId = JSONUtil.checkAndGetInt(param, "productId");
        Integer delTemplate = JSONUtil.checkAndGetInt(param, "delTemplate");
        if(delTemplate != 1 && delTemplate != 0) {
            throw new BusinessException("删除模板参数异常");
        }

        if(delTemplate == 1) {
            // 删除商品绑定的模板与参数
            Integer templateId = storeProductMapper.selectTemplateIdByStoreIdAndProductId(storeId, productId);
            if(templateId != null) {
                delTemplate(templateId);
            }
        }
        // 删除商品
        storeProductMapper.delByStoreIdAndProductId(storeId, productId);
    }

    private void delTemplate(int templateId) {
        templateParamMapper.deleteByTemplateId(templateId);
        templateMapper.deleteById(templateId);
    }

    private List<JSONObject> getTemplateDetail(List<TemplateParam> templateParamList,
                                         List<ParamItem> paramItemList,
                                         List<ParamValue> paramValueList) {
        Map<Integer, ParamItem> itemMap = paramItemList.stream().collect(Collectors.toMap(ParamItem::getId, p -> p));
        Map<Integer, ParamValue> valueMap = paramValueList.stream().collect(Collectors.toMap(ParamValue::getId, p -> p));

        // 按参数项id分类
        Map<Integer, List<ParamValue>> map = new HashMap<>();
        for (TemplateParam templateParam : templateParamList) {
            int paramValueId = templateParam.getParamValueId();
            ParamValue paramValue = valueMap.get(paramValueId);
            SystemUtil.checkErrorIfNull(paramValue, "参数值不存在");
            ParamItem paramItem = itemMap.get(paramValue.getParamItemId());
            SystemUtil.checkErrorIfNull(paramItem, "参数项不存在");

            List<ParamValue> list = map.getOrDefault(paramItem.getId(), new ArrayList<>());
            list.add(paramValue);
            map.put(paramItem.getId(), list);
        }

        List<JSONObject> paramList = new ArrayList<>();
        for (Map.Entry<Integer, List<ParamValue>> entry : map.entrySet()) {
            Integer itemId = entry.getKey();
            List<ParamValue> paramValues = entry.getValue();
            ParamItem paramItem = itemMap.get(itemId);

            JSONObject obj = ParamItem.getParamItemBaseMsg(paramItem);
            List<JSONObject> list = new ArrayList<>();
            for (ParamValue paramValue : paramValues) {
                list.add(ParamValue.getBaseMsg(paramValue));
            }

            obj.put("valueList", list);
            paramList.add(obj);
        }

        return paramList;
    }

    private List<Product> listProduct(List<Integer> productIdList) {
        if(CollectionUtil.isEmpty(productIdList)) {
            return Collections.emptyList();
        }

        QueryWrapper<Product> wrapper = new QueryWrapper<>();
        wrapper.in(Product.PRODUCT_ID, productIdList);
        return productMapper.selectList(wrapper);
    }

    private String generateStoreId() {
        String uuid = SystemUtil.uuid();
        return uuid.substring(0, 9);
    }
}
